react-linear-feedback 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +131 -0
- package/dist/react/index.cjs +627 -0
- package/dist/react/index.d.cts +109 -0
- package/dist/react/index.d.ts +109 -0
- package/dist/react/index.js +622 -0
- package/dist/server/index.cjs +170 -0
- package/dist/server/index.d.cts +85 -0
- package/dist/server/index.d.ts +85 -0
- package/dist/server/index.js +165 -0
- package/package.json +76 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Oliver Odgaard
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# react-linear-feedback
|
|
2
|
+
|
|
3
|
+
A drop-in feedback widget for any React app. A trusted user opens it with `?feedback`, **drags a box** over the page, picks **Bug / Improvement**, writes a note β and it captures an **annotated screenshot** and opens a **Linear issue**.
|
|
4
|
+
|
|
5
|
+
- πͺΆ **Framework-agnostic** β Next.js, Vite, Remix, CRAβ¦ (no `next` dependency)
|
|
6
|
+
- π¨ **Self-contained styles** β injected at runtime, themeable with one prop; **no CSS import, no Tailwind, no design system** required
|
|
7
|
+
- πΌοΈ **Annotated screenshots** via [`modern-screenshot`](https://github.com/qq15725/modern-screenshot) (handles Tailwind v4 / `oklch()`)
|
|
8
|
+
- π·οΈ **Labels resolved by name** at request time (recoloring/recreating a label in Linear won't break it), applied best-effort
|
|
9
|
+
- π Tiny server core + **Next.js & Node/Express adapters**
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i react-linear-feedback
|
|
15
|
+
# the server entry needs the Linear SDK:
|
|
16
|
+
npm i @linear/sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`react` / `react-dom` are peer dependencies. `@linear/sdk` is an optional peer β only needed where you run the server handler.
|
|
20
|
+
|
|
21
|
+
## Quick start β Next.js (App Router)
|
|
22
|
+
|
|
23
|
+
**1. Server route** β `app/api/feedback/route.ts`:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { createNextRoute, cookieGate } from "react-linear-feedback/server";
|
|
27
|
+
|
|
28
|
+
export const runtime = "nodejs"; // needs Buffer + the Linear SDK
|
|
29
|
+
|
|
30
|
+
export const POST = createNextRoute({
|
|
31
|
+
apiKey: process.env.LINEAR_API_KEY!,
|
|
32
|
+
teamId: process.env.LINEAR_TEAM_ID!,
|
|
33
|
+
authorize: cookieGate("wh_feedback"), // only allow users who enabled the tool
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**2. Mount the widget** once (e.g. in `app/layout.tsx`):
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { FeedbackGate } from "react-linear-feedback/react";
|
|
41
|
+
|
|
42
|
+
export default function RootLayout({ children }) {
|
|
43
|
+
return (
|
|
44
|
+
<html><body>
|
|
45
|
+
{children}
|
|
46
|
+
<FeedbackGate brandColor="#7f56d9" />
|
|
47
|
+
</body></html>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Visit any page with `?feedback` to turn it on (a cookie remembers it). `?feedback=0` turns it off.
|
|
53
|
+
|
|
54
|
+
## Quick start β Vite / SPA (separate backend)
|
|
55
|
+
|
|
56
|
+
Mount the widget and point it at your backend:
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { FeedbackGate } from "react-linear-feedback/react";
|
|
60
|
+
|
|
61
|
+
<FeedbackGate endpoint="https://api.example.com/feedback" brandColor="#7f56d9" />
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Run the handler on any Node server (Express shown):
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import express from "express";
|
|
68
|
+
import { createNodeHandler } from "react-linear-feedback/server";
|
|
69
|
+
|
|
70
|
+
const app = express();
|
|
71
|
+
app.post("/feedback", createNodeHandler({
|
|
72
|
+
apiKey: process.env.LINEAR_API_KEY!,
|
|
73
|
+
teamId: process.env.LINEAR_TEAM_ID!,
|
|
74
|
+
}));
|
|
75
|
+
app.listen(8787);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
(Enable CORS for your site origin if the API is on a different host.)
|
|
79
|
+
|
|
80
|
+
## Configuration
|
|
81
|
+
|
|
82
|
+
**`<FeedbackGate>` / `<FeedbackWidget>` props**
|
|
83
|
+
|
|
84
|
+
| Prop | Default | Description |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| `endpoint` | `/api/feedback` | Where the widget POSTs |
|
|
87
|
+
| `brandColor` | indigo | FAB / active / focus color (sets `--lfb-brand`) |
|
|
88
|
+
| `position` | `bottom-right` | `bottom-right` \| `bottom-left` \| `top-right` \| `top-left` |
|
|
89
|
+
| `types` | Bug, Improvement | `{ id, label, color, icon? }[]` shown in the composer |
|
|
90
|
+
| `nameRequired` | `true` | Ask for a reporter name before the first submission |
|
|
91
|
+
| `fabLabel` | `Give feedback` | Floating button text |
|
|
92
|
+
| `urlParam` | `feedback` | Toggle param (gate only) |
|
|
93
|
+
| `cookieName` | `wh_feedback` | Enabled-state cookie (gate only) |
|
|
94
|
+
|
|
95
|
+
**Server config** (`createNextRoute` / `createNodeHandler` / `createFeedbackIssue`)
|
|
96
|
+
|
|
97
|
+
| Field | Description |
|
|
98
|
+
| --- | --- |
|
|
99
|
+
| `apiKey` | Linear personal API key (**server-side only**) |
|
|
100
|
+
| `teamId` | Target team UUID |
|
|
101
|
+
| `labels` | Optional `{ [typeId]: labelName }` map. Default: the type id is the label name (so `bug` β label `bug`) |
|
|
102
|
+
| `allowedOrigin` | Optional single-origin allowlist |
|
|
103
|
+
| `authorize(req)` | Optional gate; return `false` to reject (`cookieGate` provided) |
|
|
104
|
+
|
|
105
|
+
## Theming
|
|
106
|
+
|
|
107
|
+
Set `brandColor`, or override any CSS variable on `.lfb-doc-layer, .lfb-fixed-layer`:
|
|
108
|
+
`--lfb-brand`, `--lfb-fg`, `--lfb-surface`, `--lfb-border`, `--lfb-radius`, `--lfb-rect`, `--lfb-z`, `--lfb-font`.
|
|
109
|
+
|
|
110
|
+
## Custom types
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
<FeedbackGate
|
|
114
|
+
types={[
|
|
115
|
+
{ id: "bug", label: "Bug", color: "#ef4444", icon: "bug" },
|
|
116
|
+
{ id: "idea", label: "Idea", color: "#22c55e", icon: "improvement" },
|
|
117
|
+
]}
|
|
118
|
+
/>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Each `type.id` is matched to a Linear label of the same name (or remap via the server `labels` config).
|
|
122
|
+
|
|
123
|
+
## Security
|
|
124
|
+
|
|
125
|
+
The endpoint **creates Linear issues**, so it's effectively write access to your tracker. It's gated only by what you wire up β use `authorize` (e.g. `cookieGate`, a session check) and/or `allowedOrigin`, and add rate limiting if the page is public. Your `LINEAR_API_KEY` stays server-side; the package never ships it to the browser.
|
|
126
|
+
|
|
127
|
+
> Linear asset URLs (the screenshots) are **private** β they render inside the issue but a fresh signed URL is needed to fetch them elsewhere.
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT
|